/*
 * Copyright (c) 2011-2015. ShenZhen trendit Information Technology Co.,Ltd.
 *
 * All right reserved.
 *
 * This software is the confidential and proprietary
 * information of trendit Company of China.
 * ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only
 * in accordance with the terms of the contract agreement
 * you entered into with trendit inc.
 */

package com.pagonxt.hal.platform.utils;

import android.text.TextUtils;

import java.io.UnsupportedEncodingException;

public class ByteUtils {

    public static int byte2ToInt(byte[] byte2) {
        int ret = 0;
        ret += (byte2[2] & 0xff) << 8;
        ret += (byte2[3] & 0xff);

        return ret;
    }

    public static int byte4ToInt(byte[] byte4) {
        int ret = 0;
        ret += (byte4[0] & 0xff) << 24;
        ret += (byte4[1] & 0xff) << 16;
        ret += (byte4[2] & 0xff) << 8;
        ret += (byte4[3] & 0xff);

        return ret;
    }

    /**
     * Convert a string to a byte array in ASCII encoding.
     *
     * @param str The input string.
     * @return byte[] The resulting byte array.
     */
    public static byte[] string2ASCIIByteArray(String str) {
        if (TextUtils.isEmpty(str)) {
            return null;
        }
        byte[] data = null;
        try {
            data = str.getBytes("US-ASCII");
        } catch (UnsupportedEncodingException e) {
            android.util.Log.e("xgd", "Error converting string to ASCII byte array");
            e.printStackTrace();
        }
        return data;
    }

    /**
     * Convert ASCII encoded byte array to a string.
     *
     * @param data The input byte array.
     * @return String The resulting string.
     */
    public static String asciiByteArray2String(byte[] data) {
        if (data == null) return "";
        StringBuilder tStringBuf = new StringBuilder();
        char[] tChars = new char[data.length];

        int end = 0;
        for (int i = 0; i < data.length; i++) {
            end = data.length;
            tChars[i] = (char) data[i];
        }

        tStringBuf.append(tChars, 0, end);

        return tStringBuf.toString().trim();
    }

    /**
     * Convert hex string to byte array.
     *
     * @param hexStr The input hex string.
     * @return byte[] The resulting byte array.
     */
    public static byte[] hexString2ByteArray(String hexStr) {
        if (hexStr == null) {
            return null;
        }

        if (hexStr.length() % 2 != 0) {
            return null;
        }
        byte[] data = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            char hc = hexStr.charAt(2 * i);
            char lc = hexStr.charAt(2 * i + 1);
            byte hb = hexChar2Byte(hc);
            byte lb = hexChar2Byte(lc);

            if (hb < 0 || lb < 0) {
                return null;
            }

            int n = hb << 4;
            data[i] = (byte) (n + lb);
        }

        return data;
    }

    public static short[] stringToShortArray(String randNo) {
        char[] cc = new char[randNo.length()];
        short[] shorts = new short[randNo.length()];
        randNo.getChars(0, randNo.length(), cc, 0);

        for (int i = 0; i < cc.length; ++i) {
            shorts[i] = (short) cc[i];
        }

        return shorts;
    }

    public static byte hexChar2Byte(char c) {
        if (c >= '0' && c <= '9') {
            return (byte) (c - '0');
        } else if (c >= 'a' && c <= 'f') {
            return (byte) (c - 'a' + 10);
        } else if (c >= 'A' && c <= 'F') {
            return (byte) (c - 'A' + 10);
        } else {
            return -1;
        }
    }

    public static byte[] int2HexBytes(int value) {
        String hexStr = Integer.toHexString(value);
        return ByteUtils.hexString2ByteArray(hexStr);
    }

    public static int HexBytes2Int(byte[] data) {
        String str = byteArray2HexString(data);
        return Integer.parseInt(str, 16);
    }

    /**
     * Convert byte array to hex string.
     *
     * @param arr The input byte array.
     * @return String The resulting hex string.
     */
    public static String byteArray2HexString(byte[] arr) {
        if (arr == null || arr.length == 0) {
            return null;
        }
        StringBuilder sbd = new StringBuilder();
        for (byte b : arr) {
            String tmp = Integer.toHexString(0xFF & b);
            if (tmp.length() < 2) {
                tmp = "0" + tmp;
            }
            sbd.append(tmp);
        }
        return sbd.toString();
    }

    public static String bcd2Ascii(String bcd) {
        if (TextUtils.isEmpty(bcd)) {
            return null;
        }
        char[] bcdChars = bcd.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char c : bcdChars) {
            String hex = Integer.toHexString(c);
            sb.append(hex);
        }
        return sb.toString();
    }

    public static String byteArray2HexStringWithSpace(byte[] arr) {
        StringBuilder sbd = new StringBuilder();
        for (byte b : arr) {
            String tmp = Integer.toHexString(0xFF & b);
            if (tmp.length() < 2) {
                tmp = "0" + tmp;
            }

            sbd.append(tmp);
            sbd.append("  ");
        }

        return sbd.toString();
    }

    /**
     * Convert short to byte array (high byte first).
     *
     * @param arr The input short value.
     * @return byte[] The resulting byte array.
     */
    public static byte[] short2ByteArrayHigh(short arr) {
        byte[] sbd = new byte[2];
        sbd[0] = (byte) (arr / 256);
        sbd[1] = (byte) (0xFF & arr);
        return sbd;
    }

    public static String getBCDString(byte[] data, int start, int end) {
        byte[] t = new byte[end - start + 1];
        System.arraycopy(data, start, t, 0, t.length);
        return ByteUtils.byteArray2HexString(t);
    }

    public static String getHexString(byte[] data, int start, int end) {
        byte[] t = new byte[end - start + 1];
        System.arraycopy(data, start, t, 0, t.length);
        return ByteUtils.byteArray2HexStringWithSpace(t);
    }

    public static String toHex(Integer i) {
        return Integer.toHexString((i & 0x000000ff) | 0xffffff00)
                .substring(6).toUpperCase();
    }

    // Bcd short for Binary-coded decimal
    public static byte[] str2Bcd(String str) {
        if (str == null) {
            return null;
        }
        int len = str.length();
        if (len % 2 != 0) {
            str = "0" + str;
            len = str.length();
        }

        byte[] strBytes = new byte[len];
        if (len >= 2) {
            len = len / 2;
        }

        byte[] bcd = new byte[len];
        strBytes = str.getBytes();
        int j, k;

        for (int p = 0; p < str.length() / 2; p++) {
            if ((strBytes[2 * p] >= '0') && (strBytes[2 * p] <= '9')) {
                j = strBytes[2 * p] - '0';
            } else if ((strBytes[2 * p] >= 'a') && (strBytes[2 * p] <= 'z')) {
                j = strBytes[2 * p] - 'a' + 0x0a;
            } else {
                j = strBytes[2 * p] - 'A' + 0x0a;
            }

            if ((strBytes[2 * p + 1] >= '0') && (strBytes[2 * p + 1] <= '9')) {
                k = strBytes[2 * p + 1] - '0';
            } else if ((strBytes[2 * p + 1] >= 'a') && (strBytes[2 * p + 1] <= 'z')) {
                k = strBytes[2 * p + 1] - 'a' + 0x0a;
            } else {
                k = strBytes[2 * p + 1] - 'A' + 0x0a;
            }

            int a = (j << 4) + k;
            byte b = (byte) a;
            bcd[p] = b;
        }

        return bcd;
    }

    /**
     * Convert an int value to a four-byte array, with the high byte first.
     * This method is suitable for big-endian order, where the high byte is stored first and the low byte is stored last.
     *
     * @param value The int value to be converted.
     * @return byte[] The resulting byte array.
     */
    public static byte[] intToBytes(int value) {
        byte[] src = new byte[4];
        src[0] = (byte) ((value >> 24) & 0xFF);
        src[1] = (byte) ((value >> 16) & 0xFF);
        src[2] = (byte) ((value >> 8) & 0xFF);
        src[3] = (byte) (value & 0xFF);
        return src;
    }

    public static byte[] intTo2Bytes(int len) {
        byte[] lens = new byte[2];
        lens[0] = (byte) (len >> 8);
        lens[1] = (byte) (len & 0xFF);
        return lens;
    }

    public static byte[] intTo4Bytes(int len) {
        byte[] b = new byte[4];
        b[0] = (byte) ((len >> 24) & 0xFF);
        b[1] = (byte) ((len >> 16) & 0xFF);
        b[2] = (byte) ((len >> 8) & 0xFF);
        b[3] = (byte) (len & 0xFF);
        return b;
    }

    public static byte[] subBytes(byte[] src, int begin, int count) {
        byte[] bs = new byte[count];
        System.arraycopy(src, begin, bs, 0, count);
        return bs;
    }

    public static byte[] byteTo1Bytes(byte value) {
        byte[] b = new byte[1];
        b[0] = value;
        return b;
    }

    public static byte[] createBytes(byte[]... bytes) {
        int dataLen = 0;
        for (byte[] b : bytes) {
            if (b == null) {
                continue;
            }
            dataLen = dataLen + b.length;
        }
        byte[] data = new byte[dataLen];
        int tmpDataLen = 0;
        for (byte[] b : bytes) {
            if (b == null) {
                continue;
            }
            System.arraycopy(b, 0, data, tmpDataLen, b.length);
            tmpDataLen = tmpDataLen + b.length;
        }
        return data;
    }

    /**
     * Calculate the Longitudinal Redundancy Check (LRC) for a given byte array.
     *
     * @param buffer The input byte array.
     * @param start The start index for calculating LRC.
     * @param end The end index for calculating LRC.
     * @return int The calculated LRC value.
     */
    public static int lrc(byte[] buffer, int start, int end) {
        int checkLRC = 0;
        for (int i = start; i < end; i++) {
            checkLRC ^= buffer[i];
        }
        return checkLRC;
    }
}
